
////////////////////////////////////////////////////////////////////////////////
//
// DAO.java
//
// Copyright © (C) 2010
// 
// Emory Hughes Merryman, III
// emory.merryman@gmail.com
// 
// All Rights Reserved
// 
// This file is part of Interworks.
// 
// Interworks is free software: you can 
// redistribute it and/or modify it under 
// the terms of the GNU General Public 
// License as published by the Free 
// Software Foundation, either version 3 
// of the License, or (at your option) any 
// later version.
// 
// This program is distributed in the hope 
// that it will be useful, but WITHOUT 
// ANY WARRANTY; without even the 
// implied warranty of MERCHANTABILITY 
// or FITNESS FOR A PARTICULAR 
// PURPOSE.  See the GNU General Public 
// License for more details.
//
// You should have received a copy of the 
// GNU General Public License along with 
// this program.  If not, see 
// <http://www.gnu.org/licenses/>.
////////////////////////////////////////////////////////////////////////////////

package com . superiorglobalbusiness . researchr ;

import java . util . Map ;
import java . util . HashMap ;
import java . sql . ResultSet ;
import javax . sql . DataSource ;
import org . apache . commons . logging . Log ;
import org . apache . commons . logging . LogFactory ;
import org . springframework . jdbc . core . JdbcTemplate ;
import org . springframework . stereotype . Repository ;
import org . springframework . jdbc . core . ResultSetExtractor ;
import
    org . springframework . beans . factory . annotation .
    Autowired ;

import java . sql . SQLException ;

@ Repository
    class DAO
      {
	  private static final String TAB = "\t" ;

	  private static final String NEWLINE = "\n" ;

	  private final Map < SQLSum , CharSequence > keys_ =
	      new HashMap < SQLSum , CharSequence > ( ) ;

	  private final JdbcTemplate template_ ;

	  private final Log log_ =
	      LogFactory . getLog ( this . getClass ( ) ) ;

	  @ Autowired
	      DAO ( final DataSource dataSource )
	  {
	      super ( ) ;
	      template_ = new JdbcTemplate ( dataSource ) ;
	      template_ . execute
		  (
		   "CREATE TABLE IF NOT EXISTS sum ( "
		   +
		   "implementation ENUM "
		   +
		   "( "
		   +
		   "\'R Interpreted\' , \'R Compiled\' , "
		   +
		   "\'Java\' , \'SQL Memory\' , \'SQL Disk\' ) , "
		   +
		   "sizeOfArray INTEGER , "
		   +
		   "time BIGINT ) ;" ) ;
	  }

	  void results ( )
	  {
	      ResultSetExtractor < Void > rse =
		  new ResultSetExtractor < Void > ( )
		  {
		      @ Override
		      public
		      Void
		      extractData
		      ( final ResultSet rs )
		      throws SQLException
		      {
			  StringBuilder sb = new StringBuilder ( ) ;
			  boolean next = rs . next ( ) ;
			  while ( next )
			      {
				  String implementation =
				      rs . getString ( "implementation" ) ;
				  double avg = rs . getDouble ( "avg"  ) ;
				  long min = rs . getLong ( "min" ) ;
				  long max = rs . getLong ( "max" ) ;
				  sb . append ( implementation ) ;
				  sb . append ( TAB ) ;
				  sb . append ( avg ) ;
				  sb . append ( TAB ) ;
				  sb . append ( min ) ;
				  sb . append ( TAB ) ;
				  sb . append ( max ) ;
				  sb . append ( NEWLINE ) ;
				  log_ . info ( sb ) ;
				  next = rs . next ( ) ;
			      }
			  return ( null ) ;
		      }
		  } ;
	      template_ . query
		  (
		   "SELECT implementation , "
		   +
		   "AVG(time) AS avg , "
		   +
		   "MIN(time) AS min , "
		   +
		   "MAX(time) AS max " 
		   +
		   "FROM sum "
		   +
		   "GROUP BY implementation ;" ,
		   rse
		   ) ;
	  }

	  void
	      record
	      ( final Sum sum , final int sampleSize )
	      throws Exception
	  {
	      sum . setUp ( ) ;
	      for ( int i = 0 ; i < sampleSize ; i ++ )
		  {
		      record ( sum ) ;
		  }
	      sum . tearDown ( ) ;
	  }

	  private
	      void
	      record
	      ( final Sum sum )
	      throws Exception
	  {
	      long start = System . nanoTime ( ) ;
	      sum . call ( ) ;
	      long stop = System . nanoTime ( ) ;
	      long time = stop - start ;
	      String implementation = sum . getImplementation ( ) ;
	      int sizeOfArray = sum . getSizeOfArray ( ) ;
	      template_ . update
		  (
		   "INSERT INTO sum "
		   +
		   "( implementation , sizeOfArray , time ) "
		   +
		   "VALUES ( ? , ? , ? ) ;" ,
		   implementation ,
		   sizeOfArray ,
		   time
		   ) ;
	  }

	  void createTemporaryTable
	      ( final SQLSum sum )
	  {
	      synchronized ( keys_ )
		  {
		      final StringBuilder name = new StringBuilder ( ) ;
		      name . append ( "t_" ) ;
		      int id = keys_ . size ( ) ;
		      name . append ( id ) ;
		      StringBuilder sb = new StringBuilder ( ) ;
		      sb . append ( "CREATE TEMPORARY TABLE IF NOT EXISTS " ) ;
		      sb . append ( name ) ;
		      sb . append ( " ( x TINY_INT ) " ) ;
		      String engine = sum . getEngine ( ) ;
		      sb . append ( engine ) ;
		      sb . append ( " ;" ) ;
		      String s = sb . toString ( ) ;
		      template_ . execute ( s ) ;
		      int sizeOfArray = sum . getSizeOfArray ( ) ;
		      StringBuilder inb = new StringBuilder ( ) ;
		      inb . append ( "INSERT INTO " ) ;
		      inb . append ( name ) ;
		      inb . append ( " ( x ) VALUES ( 0 ) ;" ) ;
		      String in = inb . toString ( ) ;
		      for ( int i = 0 ; i < sizeOfArray ; i ++ )
			  {
			      template_ . execute ( in ) ;
			  }
		      keys_ . put ( sum , name ) ;
		  }
	  }

	  void dropTemporaryTable ( final SQLSum sum )
	  {
	      synchronized ( keys_ )
		  {
		      StringBuilder sb = new StringBuilder ( ) ;
		      sb . append ( "DROP TEMPORARY TABLE IF EXISTS " ) ;
		      CharSequence name = keys_ . get ( sum ) ;
		      sb . append ( name ) ;
		      sb . append ( " ;" ) ;
		      String s = sb . toString ( ) ;
		      template_ . execute ( s ) ;
		      keys_ . remove ( sum ) ;
		  }			  
	  }

	  void sumTemporaryTable ( final SQLSum sum )
	  {
	      ResultSetExtractor < Integer > rse =
		  new ResultSetExtractor < Integer > ( )
		  {
		      @ Override
		      public
		      Integer
		      extractData
		      ( final ResultSet rs )
		      throws SQLException
		      {
			  boolean next = rs . next ( ) ;
			  assert next ;
			  Integer data = rs . getInt ( 1 ) ;
			  next = rs . next ( ) ;
			  assert ! next ;
			  return ( data ) ;
		      } ;
		  } ;
	      CharSequence name = keys_ . get ( sum ) ;
	      StringBuilder sb = new StringBuilder ( ) ;
	      sb . append ( "SELECT SUM(x) FROM " ) ;
	      sb . append ( name ) ;
	      String s = sb . toString ( ) ;
	      Integer data = template_ . query ( s , rse ) ;
	      assert data == 0 ;
	  }
    }
